home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / strategy / xpuzzles.3 / xpuzzles / xpuzzles-5.3.1 / xskewb / Skewb3d.c < prev    next >
C/C++ Source or Header  |  1996-02-05  |  38KB  |  1,086 lines

  1. /*
  2. # X-BASED SKEWB
  3. #
  4. #  Skewb3d.c
  5. #
  6. ###
  7. #
  8. #  Copyright (c) 1994 - 96    David Albert Bagley, bagleyd@hertz.njit.edu
  9. #
  10. #                   All Rights Reserved
  11. #
  12. #  Permission to use, copy, modify, and distribute this software and
  13. #  its documentation for any purpose and without fee is hereby granted,
  14. #  provided that the above copyright notice appear in all copies and
  15. #  that both that copyright notice and this permission notice appear in
  16. #  supporting documentation, and that the name of the author not be
  17. #  used in advertising or publicity pertaining to distribution of the
  18. #  software without specific, written prior permission.
  19. #
  20. #  This program is distributed in the hope that it will be "playable",
  21. #  but WITHOUT ANY WARRANTY; without even the implied warranty of
  22. #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  23. #
  24. */
  25.  
  26. /* Methods file for Skewb3d */
  27.  
  28. #include <stdio.h>
  29. #include <X11/IntrinsicP.h>
  30. #include <X11/Intrinsic.h>
  31. #include <X11/StringDefs.h>
  32. #include <X11/CoreP.h>
  33. #include "SkewbP.h"
  34. #include "Skewb3dP.h"
  35.  
  36. static void InitializeSkewb3D();
  37. static void ExposeSkewb3D();
  38. static void ResizeSkewb3D();
  39. static Boolean SetValuesSkewb3D();
  40. static void MoveSkewb3DTl();
  41. static void MoveSkewb3DTop();
  42. static void MoveSkewb3DTr();
  43. static void MoveSkewb3DLeft();
  44. static void MoveSkewb3DRight();
  45. static void MoveSkewb3DBl();
  46. static void MoveSkewb3DBottom();
  47. static void MoveSkewb3DBr();
  48. static void ResizePolyhedrons();
  49. static void DrawFrame();
  50. static void DiamondOffset3D();
  51. static void MapFrom3D();
  52. static void MapTo3D();
  53. static void CubeOffset3D();
  54.  
  55. static char defaultTranslationsSkewb3D[] =
  56.   "<KeyPress>q: Quit()\n\
  57.    Ctrl<KeyPress>C: Quit()\n\
  58.    <KeyPress>KP_Divide: MoveCcw()\n\
  59.    <KeyPress>Home: MoveTl()\n\
  60.    <KeyPress>KP_7: MoveTl()\n\
  61.    <KeyPress>R7: MoveTl()\n\
  62.    <KeyPress>Up: MoveTop()\n\
  63.    <KeyPress>KP_8: MoveTop()\n\
  64.    <KeyPress>R8: MoveTop()\n\
  65.    <KeyPress>Prior: MoveTr()\n\
  66.    <KeyPress>KP_9: MoveTr()\n\
  67.    <KeyPress>R9: MoveTr()\n\
  68.    <KeyPress>Left: MoveLeft()\n\
  69.    <KeyPress>KP_4: MoveLeft()\n\
  70.    <KeyPress>R10: MoveLeft()\n\
  71.    <KeyPress>Begin: MoveCw()\n\
  72.    <KeyPress>KP_5: MoveCw()\n\
  73.    <KeyPress>R11: MoveCw()\n\
  74.    <KeyPress>Right: MoveRight()\n\
  75.    <KeyPress>KP_6: MoveRight()\n\
  76.    <KeyPress>R12: MoveRight()\n\
  77.    <KeyPress>End: MoveBl()\n\
  78.    <KeyPress>KP_1: MoveBl()\n\
  79.    <KeyPress>R13: MoveBl()\n\
  80.    <KeyPress>Down: MoveBottom()\n\
  81.    <KeyPress>KP_2: MoveBottom()\n\
  82.    <KeyPress>R14: MoveBottom()\n\
  83.    <KeyPress>Next: MoveBr()\n\
  84.    <KeyPress>KP_3: MoveBr()\n\
  85.    <KeyPress>R15: MoveBr()\n\
  86.    <Btn1Down>: Select()\n\
  87.    <Btn1Up>: Release()\n\
  88.    <KeyPress>p: Practice()\n\
  89.    <Btn2Down>(2+): Practice()\n\
  90.    <Btn2Down>: PracticeMaybe()\n\
  91.    <KeyPress>r: Randomize()\n\
  92.    <Btn3Down>(2+): Randomize()\n\
  93.    <Btn3Down>: RandomizeMaybe()\n\
  94.    <KeyPress>g: Get()\n\
  95.    <KeyPress>w: Write()\n\
  96.    <KeyPress>u: Undo()\n\
  97.    <KeyPress>s: Solve()\n\
  98.    <KeyPress>o: Orientize()";
  99.  
  100. static XtActionsRec actionsListSkewb3D[] =
  101. {
  102.   {"Quit", (XtActionProc) QuitSkewb},
  103.   {"MoveCcw", (XtActionProc) MoveSkewbCcw},
  104.   {"MoveTl", (XtActionProc) MoveSkewb3DTl},
  105.   {"MoveTop", (XtActionProc) MoveSkewb3DTop},
  106.   {"MoveTr", (XtActionProc) MoveSkewb3DTr},
  107.   {"MoveLeft", (XtActionProc) MoveSkewb3DLeft},
  108.   {"MoveCw", (XtActionProc) MoveSkewbCw},
  109.   {"MoveRight", (XtActionProc) MoveSkewb3DRight},
  110.   {"MoveBl", (XtActionProc) MoveSkewb3DBl},
  111.   {"MoveBottom", (XtActionProc) MoveSkewb3DBottom},
  112.   {"MoveBr", (XtActionProc) MoveSkewb3DBr},
  113.   {"Select", (XtActionProc) SelectSkewb},
  114.   {"Release", (XtActionProc) ReleaseSkewb},
  115.   {"Practice", (XtActionProc) PracticeSkewb},
  116.   {"PracticeMaybe", (XtActionProc) PracticeSkewbMaybe},
  117.   {"Randomize", (XtActionProc) RandomizeSkewb},
  118.   {"RandomizeMaybe", (XtActionProc) RandomizeSkewbMaybe},
  119.   {"Get", (XtActionProc) GetSkewb},
  120.   {"Write", (XtActionProc) WriteSkewb},
  121.   {"Undo", (XtActionProc) UndoSkewb},
  122.   {"Solve", (XtActionProc) SolveSkewb},
  123.   {"Orientize", (XtActionProc) OrientizeSkewb}
  124. };
  125.  
  126. static XtResource resourcesSkewb3D[] =
  127. {
  128.   {XtNfaceColor0, XtCLabel, XtRString, sizeof(String),
  129.    XtOffset(SkewbWidget, skewb.faceName[0]), XtRString, "Red"},
  130.   {XtNfaceColor1, XtCLabel, XtRString, sizeof(String),
  131.    XtOffset(SkewbWidget, skewb.faceName[1]), XtRString, "Blue"},
  132.   {XtNfaceColor2, XtCLabel, XtRString, sizeof(String),
  133.    XtOffset(SkewbWidget, skewb.faceName[2]), XtRString, "White"},
  134.   {XtNfaceColor3, XtCLabel, XtRString, sizeof(String),
  135.    XtOffset(SkewbWidget, skewb.faceName[3]), XtRString, "Green"},
  136.   {XtNfaceColor4, XtCLabel, XtRString, sizeof(String),
  137.    XtOffset(SkewbWidget, skewb.faceName[4]), XtRString, "Pink"},
  138.   {XtNfaceColor5, XtCLabel, XtRString, sizeof(String),
  139.    XtOffset(SkewbWidget, skewb.faceName[5]), XtRString, "Yellow"},
  140.   {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
  141.    XtOffset(SkewbWidget, skewb.foreground), XtRString, XtDefaultForeground},
  142.   {XtNpieceBorder, XtCColor, XtRPixel, sizeof(Pixel),
  143.    XtOffset(SkewbWidget, skewb.borderColor), XtRString, XtDefaultForeground},
  144.   {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
  145.    XtOffset(SkewbWidget, core.width), XtRString, "250"},
  146.   {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
  147.    XtOffset(SkewbWidget, core.height), XtRString, "400"},
  148.   {XtNorient, XtCOrient, XtRBoolean, sizeof(Boolean),
  149.    XtOffset(SkewbWidget, skewb.orient), XtRString, "FALSE"}, /* DEFAULTORIENT */
  150.   {XtNmono, XtCMono, XtRBoolean, sizeof(Boolean),
  151.    XtOffset(SkewbWidget, skewb.mono), XtRString, "FALSE"},
  152.   {XtNface, XtCFace, XtRInt, sizeof(int),
  153.    XtOffset(SkewbWidget, skewb.currentFace), XtRString, "-1"},
  154.   {XtNpos, XtCPos, XtRInt, sizeof(int),
  155.    XtOffset(SkewbWidget, skewb.currentPosition), XtRString, "-1"},
  156.   {XtNdirection, XtCDirection, XtRInt, sizeof(int),
  157.    XtOffset(SkewbWidget, skewb.currentDirection), XtRString, "-1"},
  158.   {XtNpractice, XtCBoolean, XtRBoolean, sizeof(Boolean),
  159.    XtOffset(SkewbWidget, skewb.practice), XtRString, "FALSE"},
  160.   {XtNstart, XtCBoolean, XtRBoolean, sizeof(Boolean),
  161.    XtOffset(SkewbWidget, skewb.started), XtRString, "FALSE"},
  162.   {XtNselectCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
  163.    XtOffset(SkewbWidget, skewb.select), XtRCallback, NULL}
  164. };
  165.  
  166. Skewb3DClassRec skewb3dClassRec =
  167. {
  168.   {
  169.     (WidgetClass) &skewbClassRec,    /* superclass */
  170.     "Skewb3D",                /* class name */
  171.     sizeof(Skewb3DRec),            /* widget size */
  172.     NULL,                /* class initialize */
  173.     NULL,                /* class part initialize */
  174.     FALSE,                /* class inited */
  175.     InitializeSkewb3D,            /* initialize */
  176.     NULL,                /* initialize hook */
  177.     XtInheritRealize,            /* realize */
  178.     actionsListSkewb3D,            /* actions */
  179.     XtNumber(actionsListSkewb3D),    /* num actions */
  180.     resourcesSkewb3D,            /* resources */
  181.     XtNumber(resourcesSkewb3D),        /* num resources */
  182.     NULLQUARK,                /* xrm class */
  183.     TRUE,                /* compress motion */
  184.     TRUE,                /* compress exposure */
  185.     TRUE,                /* compress enterleave */
  186.     TRUE,                /* visible interest */
  187.     NULL,                /* destroy */
  188.     ResizeSkewb3D,            /* resize */
  189.     ExposeSkewb3D,            /* expose */
  190.     SetValuesSkewb3D,            /* set values */
  191.     NULL,                /* set values hook */
  192.     XtInheritSetValuesAlmost,        /* set values almost */
  193.     NULL,                /* get values hook */
  194.     XtInheritAcceptFocus,        /* accept focus */
  195.     XtVersion,                /* version */
  196.     NULL,                /* callback private */
  197.     defaultTranslationsSkewb3D,        /* tm table */
  198.     NULL,                /* query geometry */
  199.     NULL,                /* display accelerator */
  200.     NULL                /* extension */
  201.   },
  202.   {
  203.     0                    /* ignore */
  204.   },
  205.   {
  206.     0                    /* ignore */
  207.   }
  208. };
  209.  
  210. WidgetClass skewb3dWidgetClass = (WidgetClass) &skewb3dClassRec;
  211.  
  212. static XPoint faceLoc3D[MAXFACES][MAXORIENT];
  213. static XPoint cubeLoc3D[MAXFACES][MAXORIENT];
  214. static XPoint diamondLoc3D[MAXFACES][MAXORIENT + 1];
  215. static XPoint triangleLoc3D[MAXFACES][MAXORIENT][4];
  216. static XPoint letter3DList[MAXFACES][MAXCUBES];
  217. static XPoint orientDiamond[MAXFACES][MAXORIENT][2];
  218. static XPoint orientTriangle[MAXFACES][MAXORIENT][2];
  219.  
  220. static void InitializeSkewb3D(request, new)
  221.   Widget request, new;
  222. {
  223.   Skewb3DWidget w = (Skewb3DWidget) new;
  224.  
  225.   w->skewb.dim = 3;
  226.   ResizeSkewb3D(w);
  227. }
  228.  
  229. static void ResizeSkewb3D(w)
  230.   Skewb3DWidget w;
  231. {
  232.   XPoint tempSize;
  233.  
  234.   w->skewb.delta = 4;
  235.   w->skewb.vertical = (w->core.height >= w->core.width);
  236.   if (w->skewb.vertical) {
  237.     tempSize.y = w->core.height / MAXVIEWS;
  238.     tempSize.x = w->core.width;
  239.     if (tempSize.x >= DIVIDE(tempSize.y))
  240.     {
  241.       w->skewb3d.cubeSize.y = MAX((tempSize.y - 3 * w->skewb.delta) / 2 -
  242.         w->skewb.delta - 2, 0);
  243.       w->skewb3d.cubeSize.x = DIVIDE(w->skewb3d.cubeSize.y);
  244.     } else {
  245.       w->skewb3d.cubeSize.x = MAX((tempSize.x - 2 * w->skewb.delta - 7) / 2 -
  246.         w->skewb.delta, 0);
  247.       w->skewb3d.cubeSize.y = MULTIPLY(w->skewb3d.cubeSize.x);
  248.     }
  249.     w->skewb3d.cubeDiagonal = w->skewb3d.cubeSize.x / 2;
  250.     w->skewb3d.faceSize.x = w->skewb3d.cubeSize.x + 2 * w->skewb.delta + 1;
  251.     w->skewb3d.faceSize.y = w->skewb3d.cubeSize.y + 2 * w->skewb.delta + 1;
  252.     w->skewb3d.faceDiagonal = w->skewb3d.faceSize.x / 2;
  253.     w->skewb3d.viewSize.x = 2 * w->skewb3d.faceSize.x + 3;
  254.     w->skewb3d.viewSize.y = 2 * w->skewb3d.faceSize.y + 3;
  255.     w->skewb.puzzleSize.x = w->skewb3d.viewSize.x + 1;
  256.     w->skewb.puzzleSize.y = MAXVIEWS * w->skewb3d.viewSize.y + 1;
  257.   } else {
  258.     tempSize.x = w->core.width / MAXVIEWS;
  259.     tempSize.y = w->core.height;
  260.     if (tempSize.y >= DIVIDE(tempSize.x)) {
  261.       w->skewb3d.cubeSize.x = MAX((tempSize.x - 3 * w->skewb.delta) / 2 -
  262.         w->skewb.delta - 2, 0);
  263.       w->skewb3d.cubeSize.y = DIVIDE(w->skewb3d.cubeSize.x);
  264.     } else {
  265.       w->skewb3d.cubeSize.y = MAX((tempSize.y - 2 * w->skewb.delta - 7) / 2 -
  266.         w->skewb.delta, 0);
  267.       w->skewb3d.cubeSize.x = MULTIPLY(w->skewb3d.cubeSize.y);
  268.     }
  269.     w->skewb3d.cubeDiagonal = w->skewb3d.cubeSize.y / 2;
  270.     w->skewb3d.faceSize.y = w->skewb3d.cubeSize.y + 2 * w->skewb.delta + 1;
  271.     w->skewb3d.faceSize.x = w->skewb3d.cubeSize.x + 2 * w->skewb.delta + 1;
  272.     w->skewb3d.faceDiagonal = w->skewb3d.faceSize.y / 2;
  273.     w->skewb3d.viewSize.y = 2 * w->skewb3d.faceSize.y + 3;
  274.     w->skewb3d.viewSize.x = 2 * w->skewb3d.faceSize.x + 3;
  275.     w->skewb.puzzleSize.y = w->skewb3d.viewSize.y + 1;
  276.     w->skewb.puzzleSize.x = MAXVIEWS * w->skewb3d.viewSize.x + 1;
  277.   }
  278.   w->skewb.puzzleOffset.x = ((int) w->core.width - w->skewb.puzzleSize.x) / 2;
  279.   w->skewb.puzzleOffset.y = ((int) w->core.height - w->skewb.puzzleSize.y) /
  280.     2;
  281.   ResizePolyhedrons(w);
  282. }
  283.  
  284. static void ExposeSkewb3D(new, event, region)
  285.   Widget new;
  286.   XEvent *event;
  287.   Region region; /* Not used */
  288. {
  289.   Skewb3DWidget w = (Skewb3DWidget) new;
  290.  
  291.   if (w->core.visible) {
  292.     DrawFrame(w, w->skewb.puzzleGC);
  293.     DrawAllPolyhedrons((SkewbWidget) w);
  294.   }
  295. }
  296.  
  297. static Boolean SetValuesSkewb3D(current, request, new)
  298.   Widget current, request, new;
  299. {
  300.   Skewb3DWidget c = (Skewb3DWidget) current, w = (Skewb3DWidget) new;
  301.   Boolean redraw = FALSE;
  302.  
  303.   if (w->skewb3d.cubeSize.x != c->skewb3d.cubeSize.x) {
  304.     ResizeSkewb3D(w);
  305.     redraw = TRUE;
  306.   }
  307.   return (redraw);
  308. }
  309.  
  310. static void MoveSkewb3DTl(w, event, args, nArgs)
  311.   Skewb3DWidget w;
  312.   XEvent *event;
  313.   char *args[];
  314.   int nArgs;
  315. {
  316.   MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, TL,
  317.     (int) (event->xkey.state & ControlMask),
  318.     (int) (event->xkey.state &
  319.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
  320. }
  321.  
  322. static void MoveSkewb3DTop(w, event, args, nArgs)
  323.   Skewb3DWidget w;
  324.   XEvent *event;
  325.   char *args[];
  326.   int nArgs;
  327. {
  328.   MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, TOP,
  329.     (int) (event->xkey.state & ControlMask),
  330.     (int) (event->xkey.state &
  331.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
  332. }
  333.  
  334. static void MoveSkewb3DTr(w, event, args, nArgs)
  335.   Skewb3DWidget w;
  336.   XEvent *event;
  337.   char *args[];
  338.   int nArgs;
  339. {
  340.   MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, TR,
  341.     (int) (event->xkey.state & ControlMask),
  342.     (int) (event->xkey.state &
  343.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
  344. }
  345.  
  346. static void MoveSkewb3DLeft(w, event, args, nArgs)
  347.   Skewb3DWidget w;
  348.   XEvent *event;
  349.   char *args[];
  350.   int nArgs;
  351. {
  352.   MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, LEFT,
  353.     (int) (event->xkey.state & ControlMask),
  354.     (int) (event->xkey.state &
  355.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
  356. }
  357.  
  358. static void MoveSkewb3DRight(w, event, args, nArgs)
  359.   Skewb3DWidget w;
  360.   XEvent *event;
  361.   char *args[];
  362.   int nArgs;
  363. {
  364.   MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, RIGHT,
  365.     (int) (event->xkey.state & ControlMask),
  366.     (int) (event->xkey.state &
  367.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
  368. }
  369.  
  370. static void MoveSkewb3DBl(w, event, args, nArgs)
  371.   Skewb3DWidget w;
  372.   XEvent *event;
  373.   char *args[];
  374.   int nArgs;
  375. {
  376.   MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, BL,
  377.     (int) (event->xkey.state & ControlMask),
  378.     (int) (event->xkey.state &
  379.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
  380. }
  381.  
  382. static void MoveSkewb3DBottom(w, event, args, nArgs)
  383.   Skewb3DWidget w;
  384.   XEvent *event;
  385.   char *args[];
  386.   int nArgs;
  387. {
  388.   MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, BOTTOM,
  389.     (int) (event->xkey.state & ControlMask),
  390.     (int) (event->xkey.state &
  391.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
  392. }
  393.  
  394. static void MoveSkewb3DBr(w, event, args, nArgs)
  395.   Skewb3DWidget w;
  396.   XEvent *event;
  397.   char *args[];
  398.   int nArgs;
  399. {
  400.   MoveSkewbInput((SkewbWidget) w, event->xbutton.x, event->xbutton.y, BR,
  401.     (int) (event->xkey.state & ControlMask),
  402.     (int) (event->xkey.state &
  403.       (Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask)));
  404. }
  405.  
  406. static void ResizePolyhedrons(w)
  407.   Skewb3DWidget w;
  408. {
  409.   int face, orient, side, corner;
  410.   XPoint subcubeLoc3D[MAXFACES][MAXORIENT];
  411.   XPoint orientCubeLoc3D[2][MAXFACES][MAXORIENT];
  412.   XPoint subdiamondLoc3D[MAXFACES][MAXORIENT];
  413.   XPoint orientDiamondLoc3D[2][MAXFACES][MAXORIENT];
  414.  
  415.   w->skewb.letterOffset.x = -2;
  416.   w->skewb.letterOffset.y = 3;
  417.   w->skewb3d.viewMiddle.x = w->skewb3d.faceSize.x +
  418.     w->skewb.puzzleOffset.x;
  419.   w->skewb3d.viewMiddle.y = w->skewb3d.faceSize.y +
  420.     w->skewb.puzzleOffset.y;
  421.   for (face = 0; face < MAXFACES; face++) {
  422.     faceLoc3D[face][0].x = w->skewb3d.viewMiddle.x;
  423.     faceLoc3D[face][0].y = w->skewb3d.viewMiddle.y;
  424.     for (orient = 1; orient < MAXORIENT; orient++) {
  425.       faceLoc3D[face][orient].x = w->skewb3d.faceSize.x;
  426.       faceLoc3D[face][orient].y = w->skewb3d.faceSize.y;
  427.     }
  428.   }
  429.   if (w->skewb.vertical) {
  430.     faceLoc3D[0][1].x /= -2;
  431.     faceLoc3D[0][1].y /= -1;
  432.     faceLoc3D[0][2].y = 0;
  433.     faceLoc3D[0][3].x /= 2;
  434.  
  435.     faceLoc3D[1][1].x /= -2;
  436.     faceLoc3D[1][2].x /= -2;
  437.     faceLoc3D[1][2].y /= -1;
  438.     faceLoc3D[1][3].x /= 2;
  439.     faceLoc3D[1][3].y /= -1;
  440.  
  441.     faceLoc3D[2][1].y = 0;
  442.     faceLoc3D[2][2].x /= -2;
  443.     faceLoc3D[2][3].x /= -1;
  444.     faceLoc3D[2][3].y = 0;
  445.  
  446.     for (face = MAXFACES / 2; face < MAXFACES; face++)
  447.       faceLoc3D[face][0].y += w->skewb3d.viewSize.y + 3;
  448.  
  449.     faceLoc3D[3][1].x /= 2;
  450.     faceLoc3D[3][1].y /= -1;
  451.     faceLoc3D[3][2].x /= 2;
  452.     faceLoc3D[3][3].x /= -2;
  453.  
  454.     faceLoc3D[4][1].x /= -1;
  455.     faceLoc3D[4][1].y = 0;
  456.     faceLoc3D[4][2].x /= 2;
  457.     faceLoc3D[4][2].y /= -1;
  458.     faceLoc3D[4][3].y = 0;
  459.  
  460.     faceLoc3D[5][1].x /= 2;
  461.     faceLoc3D[5][2].x /= -1;
  462.     faceLoc3D[5][2].y = 0;
  463.     faceLoc3D[5][3].x /= -2;
  464.     faceLoc3D[5][3].y /= -1;
  465.   } else {
  466.     faceLoc3D[0][1].x /= -1;
  467.     faceLoc3D[0][1].y /= -2;
  468.     faceLoc3D[0][2].y /= -2;
  469.     faceLoc3D[0][3].y /= 2;
  470.  
  471.     faceLoc3D[1][1].x = 0;
  472.     faceLoc3D[1][2].x /= -1;
  473.     faceLoc3D[1][2].y /= -2;
  474.     faceLoc3D[1][3].x = 0;
  475.     faceLoc3D[1][3].y /= -1;
  476.  
  477.     faceLoc3D[2][1].y /= -2;
  478.     faceLoc3D[2][2].x = 0;
  479.     faceLoc3D[2][3].y /= 2;
  480.     faceLoc3D[2][3].x /= -1;
  481.  
  482.     for (face = MAXFACES / 2; face < MAXFACES; face++)
  483.        faceLoc3D[face][0].x += w->skewb3d.viewSize.x + 3;
  484.  
  485.     faceLoc3D[3][1].x /= -1;
  486.     faceLoc3D[3][1].y /= 2;
  487.     faceLoc3D[3][2].x = 0;
  488.     faceLoc3D[3][2].y /= -1;
  489.     faceLoc3D[3][3].y /= -2;
  490.  
  491.     faceLoc3D[4][1].y /= 2;
  492.     faceLoc3D[4][2].x /= -1;
  493.     faceLoc3D[4][2].y /= 2;
  494.     faceLoc3D[4][3].x /= -1;
  495.     faceLoc3D[4][3].y /= -2;
  496.  
  497.     faceLoc3D[5][1].x = 0;
  498.     faceLoc3D[5][1].y /= -1;
  499.     faceLoc3D[5][2].y /= 2;
  500.     faceLoc3D[5][3].x = 0;
  501.   }
  502.  
  503.   for (face = 0; face < MAXFACES; face++) {
  504.     cubeLoc3D[face][0].x = faceLoc3D[face][0].x;
  505.     cubeLoc3D[face][0].y = faceLoc3D[face][0].y;
  506.     subcubeLoc3D[face][0].x = faceLoc3D[face][0].x;
  507.     subcubeLoc3D[face][0].y = faceLoc3D[face][0].y;
  508.     orientCubeLoc3D[0][face][0].x = orientCubeLoc3D[1][face][0].x = 0;
  509.     orientCubeLoc3D[0][face][0].y = orientCubeLoc3D[1][face][0].y = 0;
  510.     for (orient = 1; orient < MAXORIENT; orient++) {
  511.       cubeLoc3D[face][orient].x = faceLoc3D[face][orient].x - 3 *
  512.         w->skewb.delta * faceLoc3D[face][orient].x /
  513.         w->skewb3d.faceSize.x;
  514.       cubeLoc3D[face][orient].y = faceLoc3D[face][orient].y - 3 *
  515.         w->skewb.delta * faceLoc3D[face][orient].y /
  516.         w->skewb3d.faceSize.y;
  517.       subcubeLoc3D[face][orient].x = (faceLoc3D[face][orient].x -
  518.         5 * faceLoc3D[face][orient].x * w->skewb.delta /
  519.         w->skewb3d.faceSize.x) / 2;
  520.       subcubeLoc3D[face][orient].y = (faceLoc3D[face][orient].y -
  521.         5 * faceLoc3D[face][orient].y * w->skewb.delta /
  522.         w->skewb3d.faceSize.y) / 2;
  523.       orientCubeLoc3D[0][face][orient].x = (faceLoc3D[face][orient].x -
  524.         5 * faceLoc3D[face][orient].x * w->skewb.delta /
  525.         w->skewb3d.faceSize.x) / 4;
  526.       orientCubeLoc3D[0][face][orient].y = (faceLoc3D[face][orient].y -
  527.         5 * faceLoc3D[face][orient].y * w->skewb.delta /
  528.         w->skewb3d.faceSize.y) / 4;
  529.       orientCubeLoc3D[1][face][orient].x = (faceLoc3D[face][orient].x -
  530.         7 * faceLoc3D[face][orient].x * w->skewb.delta /
  531.         w->skewb3d.faceSize.x) / 6;
  532.       orientCubeLoc3D[1][face][orient].y = (faceLoc3D[face][orient].y -
  533.         7 * faceLoc3D[face][orient].y * w->skewb.delta /
  534.         w->skewb3d.faceSize.y) / 6;
  535.     }
  536.     triangleLoc3D[face][0][1].x = subcubeLoc3D[face][1].x;
  537.     triangleLoc3D[face][0][2].x = subcubeLoc3D[face][2].x -
  538.       subcubeLoc3D[face][1].x;
  539.     triangleLoc3D[face][0][1].y = subcubeLoc3D[face][1].y;
  540.     triangleLoc3D[face][0][2].y = subcubeLoc3D[face][2].y -
  541.       subcubeLoc3D[face][1].y;
  542.     triangleLoc3D[face][1][1].x = subcubeLoc3D[face][2].x;
  543.     triangleLoc3D[face][1][2].x = -subcubeLoc3D[face][1].x -
  544.       subcubeLoc3D[face][2].x;
  545.     triangleLoc3D[face][1][1].y = subcubeLoc3D[face][2].y;
  546.     triangleLoc3D[face][1][2].y = -subcubeLoc3D[face][1].y -
  547.       subcubeLoc3D[face][2].y;
  548.     triangleLoc3D[face][2][1].x = -subcubeLoc3D[face][1].x;
  549.     triangleLoc3D[face][2][2].x = subcubeLoc3D[face][1].x -
  550.       subcubeLoc3D[face][2].x;
  551.     triangleLoc3D[face][2][1].y = -subcubeLoc3D[face][1].y;
  552.     triangleLoc3D[face][2][2].y = subcubeLoc3D[face][1].y -
  553.       subcubeLoc3D[face][2].y;
  554.     triangleLoc3D[face][3][1].x = -subcubeLoc3D[face][2].x;
  555.     triangleLoc3D[face][3][2].x = subcubeLoc3D[face][1].x +
  556.       subcubeLoc3D[face][2].x;
  557.     triangleLoc3D[face][3][1].y = -subcubeLoc3D[face][2].y;
  558.     triangleLoc3D[face][3][2].y = subcubeLoc3D[face][1].y +
  559.       subcubeLoc3D[face][2].y;
  560.     for (orient = 0; orient < MAXORIENT; orient++) {
  561.       letter3DList[face][orient].x =
  562.         (2 * triangleLoc3D[face][orient][1].x +
  563.          triangleLoc3D[face][orient][2].x) / 3;
  564.       letter3DList[face][orient].y =
  565.         (2 * triangleLoc3D[face][orient][1].y +
  566.          triangleLoc3D[face][orient][2].y) / 3;
  567.       triangleLoc3D[face][orient][3].x =
  568.         -triangleLoc3D[face][orient][1].x - triangleLoc3D[face][orient][2].x;
  569.       triangleLoc3D[face][orient][3].y =
  570.         -triangleLoc3D[face][orient][1].y - triangleLoc3D[face][orient][2].y;
  571.     }
  572.   }
  573.   w->skewb3d.cubeSize.x = w->skewb3d.faceSize.x - 2 * w->skewb.delta;
  574.   w->skewb3d.cubeSize.y = w->skewb3d.faceSize.y - 2 * w->skewb.delta;
  575.   w->skewb3d.cubeDiagonal = w->skewb3d.faceDiagonal - 2 * w->skewb.delta;
  576.   w->skewb3d.cubeDiag = w->skewb3d.faceDiagonal + 2 * w->skewb.delta;
  577.  
  578.   if (w->skewb.vertical) {
  579.     letter3DList[0][MAXORIENT].x = w->skewb3d.cubeSize.x / 4;
  580.     letter3DList[0][MAXORIENT].y = -w->skewb3d.cubeSize.y / 2 + 2;
  581.     letter3DList[1][MAXORIENT].x = -w->skewb3d.cubeDiagonal;
  582.     letter3DList[1][MAXORIENT].y = 0;
  583.     letter3DList[2][MAXORIENT].x = w->skewb3d.cubeSize.x / 4;
  584.     letter3DList[2][MAXORIENT].y = w->skewb3d.cubeSize.y / 2 - 2;
  585.     letter3DList[3][MAXORIENT].x = w->skewb3d.cubeDiagonal;
  586.     letter3DList[3][MAXORIENT].y = 0;
  587.     letter3DList[4][MAXORIENT].x = -w->skewb3d.cubeSize.x / 4;
  588.     letter3DList[4][MAXORIENT].y = -w->skewb3d.cubeSize.y / 2 + 2;
  589.     letter3DList[5][MAXORIENT].x = -w->skewb3d.cubeSize.x / 4;
  590.     letter3DList[5][MAXORIENT].y = w->skewb3d.cubeSize.y / 2 - 2;
  591.   } else {
  592.     letter3DList[0][MAXORIENT].x = 0;
  593.     letter3DList[0][MAXORIENT].y = -w->skewb3d.cubeDiagonal;
  594.     letter3DList[1][MAXORIENT].x = -w->skewb3d.cubeSize.x / 2 + 2;
  595.     letter3DList[1][MAXORIENT].y = w->skewb3d.cubeSize.y / 4;
  596.     letter3DList[2][MAXORIENT].x = w->skewb3d.cubeSize.x / 2 - 2;
  597.     letter3DList[2][MAXORIENT].y = w->skewb3d.cubeSize.y / 4;
  598.     letter3DList[3][MAXORIENT].x = -w->skewb3d.cubeSize.x / 2 + 2;
  599.     letter3DList[3][MAXORIENT].y = -w->skewb3d.cubeSize.y / 4;
  600.     letter3DList[4][MAXORIENT].x = 0;
  601.     letter3DList[4][MAXORIENT].y = w->skewb3d.cubeDiagonal;
  602.     letter3DList[5][MAXORIENT].x = w->skewb3d.cubeSize.x / 2 - 2;
  603.     letter3DList[5][MAXORIENT].y = -w->skewb3d.cubeSize.y / 4;
  604.   }
  605.  
  606.   for (face = 0; face < MAXFACES; face++) {
  607.     for (orient = 0; orient < MAXORIENT - 1; orient++) {
  608.       diamondLoc3D[face][orient].x = (cubeLoc3D[face][orient].x +
  609.         cubeLoc3D[face][orient + 1].x) / 2;
  610.       diamondLoc3D[face][orient].y = (cubeLoc3D[face][orient].y +
  611.         cubeLoc3D[face][orient + 1].y) / 2;
  612.       subdiamondLoc3D[face][orient].x = (subcubeLoc3D[face][orient].x +
  613.         subcubeLoc3D[face][orient + 1].x) / 2;
  614.       subdiamondLoc3D[face][orient].y = (subcubeLoc3D[face][orient].y +
  615.         subcubeLoc3D[face][orient + 1].y) / 2;
  616.       orientDiamondLoc3D[0][face][orient].x =
  617.         (orientCubeLoc3D[0][face][orient].x +
  618.         orientCubeLoc3D[0][face][orient + 1].x) / 2;
  619.       orientDiamondLoc3D[0][face][orient].y =
  620.         (orientCubeLoc3D[0][face][orient].y +
  621.         orientCubeLoc3D[0][face][orient + 1].y) / 2;
  622.       orientDiamondLoc3D[1][face][orient].x =
  623.         (orientCubeLoc3D[1][face][orient].x +
  624.         orientCubeLoc3D[1][face][orient + 1].x) / 2;
  625.       orientDiamondLoc3D[1][face][orient].y =
  626.         (orientCubeLoc3D[1][face][orient].y +
  627.         orientCubeLoc3D[1][face][orient + 1].y) / 2;
  628.     }
  629.     /* Its a parallelagram so take advantage of that */
  630.     diamondLoc3D[face][orient].x = (cubeLoc3D[face][MAXORIENT - 1].x -
  631.       cubeLoc3D[face][MAXORIENT / 2].x) / 2;
  632.     diamondLoc3D[face][orient].y = (cubeLoc3D[face][MAXORIENT - 1].y -
  633.       cubeLoc3D[face][MAXORIENT / 2].y) / 2;
  634.     diamondLoc3D[face][MAXORIENT].x = -diamondLoc3D[face][1].x -
  635.       diamondLoc3D[face][2].x - diamondLoc3D[face][3].x;
  636.     diamondLoc3D[face][MAXORIENT].y = -diamondLoc3D[face][1].y -
  637.       diamondLoc3D[face][2].y - diamondLoc3D[face][3].y;
  638.  
  639.     subdiamondLoc3D[face][orient].x = (subcubeLoc3D[face][MAXORIENT - 1].x -
  640.       subcubeLoc3D[face][MAXORIENT / 2].x) / 2;
  641.     subdiamondLoc3D[face][orient].y = (subcubeLoc3D[face][MAXORIENT - 1].y -
  642.       subcubeLoc3D[face][MAXORIENT / 2].y) / 2;
  643.     orientDiamondLoc3D[0][face][orient].x =
  644.       (orientCubeLoc3D[0][face][MAXORIENT - 1].x -
  645.       orientCubeLoc3D[0][face][MAXORIENT / 2].x) / 2;
  646.     orientDiamondLoc3D[0][face][orient].y =
  647.       (orientCubeLoc3D[0][face][MAXORIENT - 1].y -
  648.       orientCubeLoc3D[0][face][MAXORIENT / 2].y) / 2;
  649.     orientDiamondLoc3D[1][face][orient].x =
  650.       (orientCubeLoc3D[1][face][MAXORIENT - 1].x -
  651.       orientCubeLoc3D[1][face][MAXORIENT / 2].x) / 2;
  652.     orientDiamondLoc3D[1][face][orient].y =
  653.       (orientCubeLoc3D[1][face][MAXORIENT - 1].y -
  654.       orientCubeLoc3D[1][face][MAXORIENT / 2].y) / 2;
  655.  
  656.     MapFrom3D(face, 1, &corner);
  657.     orientDiamond[face][corner][0].x = cubeLoc3D[face][1].x / 2;
  658.     orientDiamond[face][corner][0].y = cubeLoc3D[face][1].y / 2;
  659.     orientDiamond[face][corner][1].x = orientDiamond[face][corner][0].x +
  660.       (cubeLoc3D[face][2].x - subcubeLoc3D[face][2].x) / 2;
  661.     orientDiamond[face][corner][1].y = orientDiamond[face][corner][0].y +
  662.       (cubeLoc3D[face][2].y - subcubeLoc3D[face][2].y) / 2;
  663.     orientTriangle[face][corner][0].x = -orientCubeLoc3D[0][face][2].x / 2;
  664.     orientTriangle[face][corner][0].y = -orientCubeLoc3D[0][face][2].y / 2;
  665.     orientTriangle[face][corner][1].x = -orientCubeLoc3D[1][face][2].x / 2;
  666.     orientTriangle[face][corner][1].y = -orientCubeLoc3D[1][face][2].y / 2;
  667.     for (orient = 1; orient < MAXORIENT; orient++) {
  668.       side = corner;
  669.       MapFrom3D(face, (orient + 1) % MAXORIENT, &corner);
  670.       orientDiamond[face][corner][0].x =
  671.         orientDiamond[face][side][0].x +
  672.         diamondLoc3D[face][orient].x;
  673.       orientDiamond[face][corner][0].y =
  674.         orientDiamond[face][side][0].y +
  675.         diamondLoc3D[face][orient].y;
  676.       orientDiamond[face][corner][1].x =
  677.         orientDiamond[face][side][1].x +
  678.         subdiamondLoc3D[face][orient].x;
  679.       orientDiamond[face][corner][1].y =
  680.         orientDiamond[face][side][1].y +
  681.         subdiamondLoc3D[face][orient].y;
  682.       orientTriangle[face][corner][0].x =
  683.         orientTriangle[face][side][0].x +
  684.         orientDiamondLoc3D[0][face][orient].x;
  685.       orientTriangle[face][corner][0].y =
  686.         orientTriangle[face][side][0].y +
  687.         orientDiamondLoc3D[0][face][orient].y;
  688.       orientTriangle[face][corner][1].x =
  689.         orientTriangle[face][side][1].x +
  690.         orientDiamondLoc3D[1][face][orient].x;
  691.       orientTriangle[face][corner][1].y =
  692.         orientTriangle[face][side][1].y +
  693.         orientDiamondLoc3D[1][face][orient].y;
  694.     }
  695.   }
  696. }
  697.  
  698. int SelectPolyhedrons3D(w, x, y, face, position)
  699.   Skewb3DWidget w;
  700.   int x, y;
  701.   int *face, *position;
  702. {
  703.   int u, v, front, tl, ur, ul, found, side, x1, y1, x2, y2, dx, dy;
  704.  
  705.   x1 = x;
  706.   y1 = y;
  707.   if (w->skewb.vertical) {
  708.     x -= w->skewb3d.viewMiddle.x;
  709.     front = (y < w->skewb3d.viewSize.y);
  710.     if (!front)
  711.       y -= (w->skewb3d.viewSize.y);
  712.     tl = (y < w->skewb3d.viewMiddle.y);
  713.     y -= w->skewb3d.viewMiddle.y;
  714.     u = -w->skewb3d.faceSize.y * x + w->skewb3d.faceDiagonal * y;
  715.     v = w->skewb3d.faceSize.y * x + w->skewb3d.faceDiagonal * y;
  716.     ur = (u < 0);
  717.     ul = (v < 0);
  718.     if (front) {
  719.       if (tl)
  720.         *face = (ur) ? 0 : 1;
  721.       else
  722.         *face = (ul) ? 1 : 2;
  723.     } else {
  724.       if (tl)
  725.         *face = (ul) ? 4 : 3;
  726.       else
  727.         *face = (ur) ? 3 : 5;
  728.     }
  729.   } else {
  730.     y -= w->skewb3d.viewMiddle.y;
  731.     front = (x < w->skewb3d.viewSize.x);
  732.     if (!front)
  733.       x -= (w->skewb3d.viewSize.x);
  734.     tl = (x < w->skewb3d.viewMiddle.x);
  735.     x -= w->skewb3d.viewMiddle.x;
  736.     u = -w->skewb3d.faceSize.x * y + w->skewb3d.faceDiagonal * x;
  737.     v = w->skewb3d.faceSize.x * y + w->skewb3d.faceDiagonal * x;
  738.     ur = (u < 0);
  739.     ul = (v < 0);
  740.     if (front) {
  741.       if (tl)
  742.         *face = (ur) ? 1 : 0;
  743.       else
  744.         *face = (ul) ? 0 : 2;
  745.     } else {
  746.       if (tl)
  747.         *face = (ul) ? 3 : 4;
  748.       else
  749.         *face = (ur) ? 4 : 5;
  750.     }
  751.   }
  752.   x = x1;
  753.   y = y1;
  754.   found = 0;
  755.   DiamondOffset3D(w, *face, &dx, &dy);
  756.   for (side = 0; side < MAXORIENT; side++) {
  757.     x1 = dx + orientDiamond[*face][side][0].x;
  758.     y1 = dy + orientDiamond[*face][side][0].y;
  759.     x2 = dx + orientDiamond[*face][(side + 1) % MAXORIENT][0].x;
  760.     y2 = dy + orientDiamond[*face][(side + 1) % MAXORIENT][0].y;
  761.     if ((x2 - x1) * (y - y1) <= (y2 - y1) * (x - x1)) {
  762.       *position = side;
  763.       found++;
  764.     }
  765.   }
  766.   if (found == 0)
  767.     *position = MAXORIENT;
  768.   else if (found > 1)
  769.     return FALSE;
  770.   return TRUE;
  771. }
  772.  
  773. int NarrowSelection3D(w, face, position, direction)
  774.   Skewb3DWidget w;
  775.   int *face;
  776.   int *position;
  777.   int *direction;
  778. {
  779.   switch (*direction) {
  780.     case TR:
  781.     case BR:
  782.     case BL:
  783.     case TL:
  784.       if (w->skewb.vertical) {
  785.         if (*face == 1) 
  786.           *direction = *direction + 2 * MAXORIENT;
  787.         else if (*face == 3)
  788.           *direction = (*direction + 3) % MAXORIENT + 2 * MAXORIENT;
  789.       } else {
  790.         if (*face == 0)
  791.           *direction = (*direction + 3) % MAXORIENT + 2 * MAXORIENT;
  792.         else if (*face == 4)
  793.           *direction = (*direction + 2) % MAXORIENT + 2 * MAXORIENT;
  794.         else if (*face == 5)
  795.           *direction = (*direction + 2) % MAXORIENT;
  796.       }
  797.       break;
  798.     case CCW:
  799.     case CW:
  800.       break;
  801.     case TOP:
  802.     case RIGHT:
  803.     case BOTTOM:
  804.     case LEFT:
  805.       if (w->skewb.vertical) {
  806.         if (*face == 1)
  807.           *direction = (TL + *direction) % MAXORIENT;
  808.         else if (*face == 3)
  809.           *direction = (BL + *direction) % MAXORIENT;
  810.       } else {
  811.         if (*face == 0)
  812.           *direction = (TR + *direction) % MAXORIENT;
  813.         else if (*face == 4)
  814.           *direction = (BR + *direction) % MAXORIENT;
  815.         else if (*face == 5)
  816.           *direction = (BL + *direction) % MAXORIENT + 2 * MAXORIENT;
  817.       }
  818.       break;
  819.     default:
  820.       return FALSE;
  821.   }
  822.   if (*position != MAXORIENT) {
  823.     if (*direction == CW)
  824.       *direction = (*position + 1) % MAXORIENT;
  825.     else if (*direction == CCW)
  826.       *direction = (*position + 3) % MAXORIENT;
  827.     else if (*direction < MAXORIENT && !((*direction + *position) % 2))
  828.       return FALSE;
  829.   }
  830.   return TRUE;
  831. }
  832.  
  833. static void DrawFrame(w, gc)
  834.   Skewb3DWidget w;
  835.   GC gc;
  836. {
  837.   int face, dx, dy;
  838.  
  839.   dx = w->skewb3d.viewSize.x + w->skewb.puzzleOffset.x;
  840.   dy = w->skewb3d.viewSize.y + w->skewb.puzzleOffset.y;
  841.   if (w->skewb.vertical) {
  842.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  843.       0, dy, dx + w->skewb.puzzleOffset.x + 1, dy);
  844.     XDrawString(XtDisplay(w), XtWindow(w), gc,
  845.       (int) (2 * w->skewb.delta),
  846.       (int) (3 * w->skewb.delta + w->skewb.letterOffset.y),
  847.       "Front", 5);
  848.     XDrawString(XtDisplay(w), XtWindow(w), gc, (int)
  849.       (-4 * w->skewb.delta + 2 * 4 * w->skewb.letterOffset.x + w->core.width), 
  850.       (int) (-w->skewb.delta - 2 * w->skewb.letterOffset.y + w->core.height),
  851.       "Back", 4);
  852.   } else {
  853.     XDrawLine(XtDisplay(w), XtWindow(w), gc,
  854.       dx, 0, dx, dy + w->skewb.puzzleOffset.y + 1);
  855.     XDrawString(XtDisplay(w), XtWindow(w), gc,
  856.       (int) (2 * w->skewb.delta),
  857.       (int) (3 * w->skewb.delta + w->skewb.letterOffset.y),
  858.       "Front", 5);
  859.     XDrawString(XtDisplay(w), XtWindow(w), gc, (int)
  860.       (-4 * w->skewb.delta + 2 * 4 * w->skewb.letterOffset.x + w->core.width), 
  861.       (int) (-w->skewb.delta - 2 * w->skewb.letterOffset.y + w->core.height),
  862.       "Back", 4);
  863.   }
  864.   for (face = 0; face < MAXFACES; face++)
  865.     XDrawLines(XtDisplay(w), XtWindow(w), gc,
  866.       faceLoc3D[face], MAXORIENT, CoordModePrevious);
  867. }   
  868.  
  869. void DrawDiamond3D(w, face)
  870.   Skewb3DWidget w;
  871.   int face;
  872. {
  873.   int dx, dy;
  874.  
  875.   DiamondOffset3D(w, face, &dx, &dy);
  876.   diamondLoc3D[face][0].x = dx + cubeLoc3D[face][1].x / 2;
  877.   diamondLoc3D[face][0].y = dy + cubeLoc3D[face][1].y / 2;
  878.   XFillPolygon(XtDisplay(w), XtWindow(w),
  879.     w->skewb.faceGC[w->skewb.cubeLoc[face][MAXORIENT].face],
  880.     diamondLoc3D[face], 4, Convex, CoordModePrevious);
  881.   XDrawLines(XtDisplay(w), XtWindow(w),
  882.     w->skewb.borderGC, diamondLoc3D[face], 5, CoordModePrevious);
  883.   if (w->skewb.depth == 1 || w->skewb.mono) {
  884.     int letterX, letterY;
  885.     char buf[2];
  886.  
  887.     (void) sprintf (buf, "%c",
  888.       w->skewb.faceName[w->skewb.cubeLoc[face][MAXORIENT].face][0]);
  889.     letterX = dx + letter3DList[face][MAXORIENT].x + w->skewb.letterOffset.x;
  890.     letterY = dy + letter3DList[face][MAXORIENT].y + w->skewb.letterOffset.y;
  891.     XDrawString(XtDisplay(w), XtWindow(w), w->skewb.inverseGC,
  892.       letterX, letterY, buf, 1);
  893.   }
  894.   if (w->skewb.orient)
  895.     XDrawLine(XtDisplay(w), XtWindow(w), w->skewb.inverseGC,
  896.       dx +
  897.         orientDiamond[face][w->skewb.cubeLoc[face][MAXORIENT].rotation][0].x,
  898.       dy +
  899.         orientDiamond[face][w->skewb.cubeLoc[face][MAXORIENT].rotation][0].y,
  900.       dx +
  901.         orientDiamond[face][w->skewb.cubeLoc[face][MAXORIENT].rotation][1].x,
  902.       dy +
  903.         orientDiamond[face][w->skewb.cubeLoc[face][MAXORIENT].rotation][1].y);
  904. }
  905.  
  906. void DrawTriangle3D(w, face, position, offset)
  907.   Skewb3DWidget w;
  908.   int face, position, offset;
  909. {
  910.   int side, dx, dy, letterX, letterY;
  911.  
  912.   MapTo3D(face, position, &side);
  913.   CubeOffset3D(w, face, side, &dx, &dy);
  914.   letterX = dx + letter3DList[face][side].x;
  915.   letterY = dy + letter3DList[face][side].y;
  916.   triangleLoc3D[face][side][0].x = dx;
  917.   triangleLoc3D[face][side][0].y = dy;
  918.   if (offset) {
  919.     XFillPolygon(XtDisplay(w), XtWindow(w),
  920.       w->skewb.borderGC,
  921.       triangleLoc3D[face][side], 3, Convex, CoordModePrevious);
  922.     XDrawLines(XtDisplay(w), XtWindow(w),
  923.       w->skewb.faceGC[w->skewb.cubeLoc[face][position].face],
  924.       triangleLoc3D[face][side], 4, CoordModePrevious);
  925.   } else {
  926.     XFillPolygon(XtDisplay(w), XtWindow(w),
  927.       w->skewb.faceGC[w->skewb.cubeLoc[face][position].face],
  928.       triangleLoc3D[face][side], 3, Convex, CoordModePrevious);
  929.     XDrawLines(XtDisplay(w), XtWindow(w),
  930.       w->skewb.borderGC, triangleLoc3D[face][side], 4, CoordModePrevious);
  931.   }
  932.   if (w->skewb.depth == 1 || w->skewb.mono) {
  933.     char buf[2];
  934.  
  935.     (void) sprintf (buf, "%c",
  936.       w->skewb.faceName[w->skewb.cubeLoc[face][position].face][0]);
  937.     XDrawString(XtDisplay(w), XtWindow(w), w->skewb.inverseGC,
  938.       letterX + w->skewb.letterOffset.x, letterY + w->skewb.letterOffset.y,
  939.       buf, 1);
  940.   }
  941.   if (w->skewb.orient)
  942.     XDrawLine(XtDisplay(w), XtWindow(w), w->skewb.inverseGC,
  943.       letterX +
  944.         orientTriangle[face][w->skewb.cubeLoc[face][position].rotation][0].x,
  945.       letterY +
  946.         orientTriangle[face][w->skewb.cubeLoc[face][position].rotation][0].y,
  947.       letterX +
  948.         orientTriangle[face][w->skewb.cubeLoc[face][position].rotation][1].x,
  949.       letterY +
  950.         orientTriangle[face][w->skewb.cubeLoc[face][position].rotation][1].y);
  951. }
  952.  
  953. static void MapTo3D(face, side, corner)
  954.   int face, side, *corner;
  955. {
  956.   switch (face) {
  957.     case 0:
  958.       *corner = (side + 2) % MAXORIENT;
  959.       break;
  960.     case 1:
  961.     case 5:
  962.       *corner = side;
  963.       break;
  964.     case 2:
  965.       *corner = (side + 1) % MAXORIENT;
  966.       break;
  967.     case 3:
  968.     case 4:
  969.       *corner = (side + 3) % MAXORIENT;
  970.       break;
  971.     default:
  972.       (void) printf ("MapTo3D: face %d\n", face);
  973.   }
  974. }
  975.  
  976. static void MapFrom3D(face, corner, side)
  977.   int face, corner, *side;
  978. {
  979.   switch (face) {
  980.     case 0:
  981.       *side = (corner + 2) % MAXORIENT;
  982.       break;
  983.     case 1:
  984.     case 5:
  985.       *side = corner;
  986.       break;
  987.     case 2:
  988.       *side = (corner + 3) % MAXORIENT;
  989.       break;
  990.     case 3:
  991.     case 4:
  992.       *side = (corner + 1) % MAXORIENT;
  993.       break;
  994.     default:
  995.       (void) printf ("MapFrom3D: face %d\n", face);
  996.   }
  997. }
  998.  
  999. static void DiamondOffset3D(w, face, dx, dy)
  1000.   Skewb3DWidget w;
  1001.   int face, *dx, *dy;
  1002. {
  1003.   if (w->skewb.vertical) {
  1004.     switch (face) {
  1005.       case 0:
  1006.         *dx = w->skewb3d.viewMiddle.x + w->skewb.delta - 1;
  1007.         *dy = w->skewb3d.viewMiddle.y - w->skewb.delta - 2;
  1008.         break;
  1009.       case 1:
  1010.         *dx = w->skewb3d.viewMiddle.x - 2 * w->skewb.delta;
  1011.         *dy = w->skewb3d.viewMiddle.y;
  1012.         break;
  1013.       case 2:
  1014.         *dx = w->skewb3d.viewMiddle.x + w->skewb.delta - 1;
  1015.         *dy = w->skewb3d.viewMiddle.y + 2 * w->skewb.delta - 1;
  1016.         break;
  1017.       case 3:
  1018.         *dx = w->skewb3d.viewMiddle.x + 2 * w->skewb.delta;
  1019.         *dy = w->skewb3d.viewSize.y + w->skewb3d.viewMiddle.y +
  1020.               w->skewb.delta - 1;
  1021.         break;
  1022.       case 4:
  1023.         *dx = w->skewb3d.viewMiddle.x - w->skewb.delta + 1;
  1024.         *dy = w->skewb3d.viewSize.y + w->skewb3d.viewMiddle.y -
  1025.               w->skewb.delta + 1;
  1026.         break;
  1027.       case 5:
  1028.         *dx = w->skewb3d.viewMiddle.x - 2;
  1029.         *dy = w->skewb3d.viewSize.y + w->skewb3d.viewMiddle.y +
  1030.               2 * w ->skewb.delta + 2;
  1031.         break;
  1032.       default:
  1033.         (void) printf ("DiamondOffset3D: face %d\n", face);
  1034.     }
  1035.   }
  1036.   else
  1037.   {
  1038.     switch (face)
  1039.     {
  1040.       case 0:
  1041.         *dx = w->skewb3d.viewMiddle.x;
  1042.         *dy = w->skewb3d.viewMiddle.y - 2 * w->skewb.delta + 1;
  1043.         break;
  1044.       case 1:
  1045.         *dx = w->skewb3d.viewMiddle.x - w->skewb.delta - 2;
  1046.         *dy = w->skewb3d.viewMiddle.y + w->skewb.delta;
  1047.         break;
  1048.       case 2:
  1049.         *dx = w->skewb3d.viewMiddle.x  + 2 * w->skewb.delta - 1;
  1050.         *dy = w->skewb3d.viewMiddle.y + w->skewb.delta;
  1051.         break;
  1052.       case 3:
  1053.         *dx = w->skewb3d.viewSize.x + w->skewb3d.viewMiddle.x -
  1054.               w->skewb.delta + 1;
  1055.         *dy = w->skewb3d.viewMiddle.y - w->skewb.delta;
  1056.         break;
  1057.       case 4:
  1058.         *dx = w->skewb3d.viewSize.x + w->skewb3d.viewMiddle.x +
  1059.               w->skewb.delta - 1;
  1060.         *dy = w->skewb3d.viewMiddle.y  + 2 * w->skewb.delta;
  1061.         break;
  1062.       case 5:
  1063.         *dx = w->skewb3d.viewSize.x + w->skewb3d.viewMiddle.x +
  1064.               2 * w->skewb.delta + 2;
  1065.         *dy = w->skewb3d.viewMiddle.y - w->skewb.delta;
  1066.         break;
  1067.       default:
  1068.         (void) printf ("DiamondOffset3D: face %d\n", face);
  1069.     }
  1070.   }
  1071. }
  1072.  
  1073. static void CubeOffset3D(w, face, corner, dx, dy)
  1074.   Skewb3DWidget w;
  1075.   int face, corner, *dx, *dy;
  1076. {
  1077.   int side;
  1078.  
  1079.   DiamondOffset3D(w, face, dx, dy);
  1080.   for (side = 1; side <= corner; side++)
  1081.   {
  1082.     *dx += cubeLoc3D[face][side].x;
  1083.     *dy += cubeLoc3D[face][side].y;
  1084.   }
  1085. }
  1086.